package com.tbit.uqbike.protocol.AnalyzeImpl;

import com.alibaba.fastjson.JSON;
import com.tbit.uqbike.protocol.ABaseHandleObj;
import com.tbit.uqbike.protocol.ATerPkg;
import com.tbit.uqbike.protocol.ATerPkgHead;
import com.tbit.uqbike.tergateway.codedifine.AlarmExCode;
import com.tbit.uqbike.tergateway.data.TerGatewayData;
import com.tbit.uqbike.tergateway.entity.AConnInfo;
import com.tbit.uqbike.tergateway.entity.CarExData;
import com.tbit.uqbike.tergateway.entity.RemoteControl;
import com.tbit.uqbike.tergateway.entity.TerSoftInfo;
import com.tbit.uqbike.tergateway.entity.TerTempData;
import com.tbit.uqbike.tergateway.wa206pkg.*;
import com.tbit.uqbike.tergateway.wa206pkg.extend.BleInfo;
import com.tbit.uqbike.tergateway.wa206pkg.extend.CellInfo;
import com.tbit.uqbike.tergateway.wa206pkg.extend.MuPos;
import com.tbit.uqbike.tergateway.wa206pkg.extend.WifiInfo;
import com.tbit.uqbike.tergateway.wa206pkg.extend.XiaomujiBase;
import com.tbit.uqbike.tergateway.wa206pkg.extend.XiaomujiCalRecoup;
import com.tbit.uqbike.tergateway.wa206pkg.extend.XiaomujiCalRet;
import com.tbit.uqbike.tergateway.wa206pkg.extend.XiaomujiTlv;
import com.tbit.uqbike.util.ByteUtil;
import com.tbit.uqbike.util.CharsetName;
import com.tbit.uqbike.util.ConstDefine;
import com.tbit.uqbike.util.ErrorCode;
import com.tbit.uqbike.util.ProtocolUtil;
import com.tbit.uqbike.util.TbitTEAUtil;
import com.tbit.utils.BitUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

/**
 * Created by MyWin on 2017/4/27.
 * 应用于终端版本小于等于：NS_QIHAO_EBIKE_WA-206_R.62.0.1_04-19-2017 14:07:22 &T650_G.C.6531DA_W_UBLOX_BLE_ECU_
 */
public class WA206DeEnCoder extends AProtocol {
    private static Logger logger = LoggerFactory.getLogger(WA206DeEnCoder.class);
    public static final String protocolName = "WA206";

    static {
        //AAutoProtocol.regProtocol(new WA205DeEnCoder());
    }

    public ByteBuf builtRemoteControlPkg(AConnInfo info, int serNo, ABaseHandleObj aBaseHandleObj) {
        logger.info(String.format("Down serNO:[%d] from [%s]", serNo, aBaseHandleObj.toString()));
        ByteBuf byteBuf = null;
        RemoteControl remoteControl = (RemoteControl) aBaseHandleObj;
        try {
            byteBuf = PooledByteBufAllocator.DEFAULT.directBuffer();
            WA206Head wa206Head = getWA206Head(info, (byte) serNo);
            //region body
            int start = 0;
            if (ConstDefine.CONTROL_TYPE_GET.equals(remoteControl.controlType)) {
                wa206Head.cmd = WA206Head.GetParamCmd;
                byteBuf = wa206Head.writePkgByte(byteBuf);
                start = byteBuf.readableBytes();
                byte[] paramBytes = remoteControl.paramName.getBytes(CharsetName.US_ASCII);
                byteBuf.writeBytes(paramBytes);
            } else if (ConstDefine.CONTROL_TYPE_SET.equals(remoteControl.controlType)) {
                wa206Head.cmd = WA206Head.SetParamCmd;
                byteBuf = wa206Head.writePkgByte(byteBuf);
                start = byteBuf.readableBytes();
                byte[] paramBytes = remoteControl.paramName.getBytes(CharsetName.US_ASCII);
                byteBuf.writeBytes(paramBytes);
            } else if (ConstDefine.CONTROL_TYPE_CONTROL.equals(remoteControl.controlType)) {
                wa206Head.cmd = WA206Head.RemoteControlCmd;
                byteBuf = wa206Head.writePkgByte(byteBuf);
                start = byteBuf.readableBytes();
                byteBuf.writeByte(Integer.parseInt(remoteControl.paramName));
            } else if (ConstDefine.CONTROL_TYPE_SMS.equals(remoteControl.controlType)) {
                wa206Head.cmd = WA206Head.RemoteSmsCmd;
                byteBuf = wa206Head.writePkgByte(byteBuf);
                start = byteBuf.readableBytes();
                byte[] phone = ByteUtil.HexStringToBytesEndMask(remoteControl.paramName, 'F', 10);
                byte[] content = remoteControl.paramValue.getBytes(CharsetName.UTF_16LE);
                byteBuf.writeBytes(phone);
                byteBuf.writeBytes(content);
            } else if (ConstDefine.CONTROL_TYPE_VOICE.equals(remoteControl.controlType)) {
                wa206Head.cmd = WA206Head.RemoteConVoiceCmd;
                byteBuf = wa206Head.writePkgByte(byteBuf);
                start = byteBuf.readableBytes();
                byteBuf.writeByte(Integer.parseInt(remoteControl.paramName));
            }
            int end = byteBuf.readableBytes();
            if ((wa206Head.version % 2) != 0) {
                byteBuf = encryptBody(byteBuf, start, end);
            }
//endregion
            // 设置长度
            byteBuf.setShort(2, byteBuf.readableBytes() + 2);
            byteBuf.writeShort(ProtocolUtil.GetCrcByteArray(byteBuf, 2, byteBuf.readableBytes() - 2));//校验和
            return byteBuf;
        } catch (Exception e) {
            byteBuf.clear();
            logger.error("构造下行数据包异常", e);
            return null;
        }
    }

    private WA206Head getWA206Head(AConnInfo info, byte serNo) {
        WA206Head wa206Head = WA206Head.getWA206Head(info.version, info.reserve, serNo);
        return wa206Head;
    }

    @Override
    public ByteBuf builtRemoteControlPkg(AConnInfo conn, ABaseHandleObj aBaseHandleObj) {
        ByteBuf byteBuf = null;
        RemoteControl remoteControl = (RemoteControl) aBaseHandleObj;
        // 格式化一下
        if (ConstDefine.CONTROL_TYPE_GET.equals(remoteControl.controlType) || ConstDefine.CONTROL_TYPE_SET.equals(remoteControl.controlType)) {
            if (remoteControl.paramName != null) {
                if (!remoteControl.paramName.endsWith(";")) {
                    remoteControl.paramName = String.format("%s;", remoteControl.paramName);
                }
            }
        }
        try {
            if (!ConstDefine.CONTROL_TYPE_SMS.equals(remoteControl.controlType)) {
                byteBuf = PooledByteBufAllocator.DEFAULT.directBuffer();
                WA206Head wa206Head = getWA206Head(conn, (byte) 0);
                int start = 0;
                if (ConstDefine.CONTROL_TYPE_GET.equals(remoteControl.controlType)) {
                    wa206Head.cmd = WA206Head.GetParamCmd;
                    byteBuf = wa206Head.writePkgByte(byteBuf);
                    start = byteBuf.readableBytes();
                    byte[] paramBytes = remoteControl.paramName.getBytes(CharsetName.US_ASCII);
                    byteBuf.writeBytes(paramBytes);
                    byte[] msgId = remoteControl.serNO.getBytes(CharsetName.US_ASCII);
                    byteBuf.writeBytes(msgId);
                } else if (ConstDefine.CONTROL_TYPE_SET.equals(remoteControl.controlType)) {
                    wa206Head.cmd = WA206Head.SetParamCmd;
                    byteBuf = wa206Head.writePkgByte(byteBuf);
                    start = byteBuf.readableBytes();
                    byte[] paramBytes = remoteControl.paramName.getBytes(CharsetName.US_ASCII);
                    byteBuf.writeBytes(paramBytes);
                    byte[] msgId = remoteControl.serNO.getBytes(CharsetName.US_ASCII);
                    byteBuf.writeBytes(msgId);
                } else if (ConstDefine.CONTROL_TYPE_CONTROL.equals(remoteControl.controlType)) {
                    wa206Head.cmd = WA206Head.RemoteControlCmd;
                    byteBuf = wa206Head.writePkgByte(byteBuf);
                    start = byteBuf.readableBytes();
                    byteBuf.writeByte(Integer.parseInt(remoteControl.paramName));
                    //
                    if (remoteControl.paramValue != null && !remoteControl.paramValue.isEmpty()) {
                        byte [] nameBytes = remoteControl.paramValue.getBytes(CharsetName.US_ASCII);
                        byteBuf.writeShort(nameBytes.length);
                        byteBuf.writeBytes(nameBytes);
                    }

                    byte[] msgId = remoteControl.serNO.getBytes(CharsetName.US_ASCII);
                    byteBuf.writeBytes(msgId);
                } else if (ConstDefine.CONTROL_TYPE_VOICE.equals(remoteControl.controlType)) {
                    wa206Head.cmd = WA206Head.RemoteConVoiceCmd;
                    byteBuf = wa206Head.writePkgByte(byteBuf);
                    start = byteBuf.readableBytes();
                    byteBuf.writeByte(Integer.parseInt(remoteControl.paramName));
                    byte[] msgId = remoteControl.serNO.getBytes(CharsetName.US_ASCII);
                    byteBuf.writeBytes(msgId);
                } else {
                    byteBuf.clear();
                    logger.error(String.format("构造下行数据包异常,未知的指令类型:[%s]", remoteControl.controlType));
                    return null;
                }
                int end = byteBuf.readableBytes();
                if ((wa206Head.version % 2) != 0) {
                    byteBuf = encryptBody(byteBuf, start, end);
                }
                // 设置长度
                byteBuf.setShort(2, byteBuf.readableBytes() + 2);
                byteBuf.writeShort(ProtocolUtil.GetCrcByteArray(byteBuf, 2, byteBuf.readableBytes() - 2));//校验和
                // 创建完成 写入全局缓存
                TerGatewayData.setStrSerNoMap(remoteControl.serNO, remoteControl);
                return byteBuf;
            } else {
                // 获取流水号
                // 主动下发指令需要有流水号
                TerTempData terTempData = TerGatewayData.getTerTempDataByMno(remoteControl.sn);
                int serNo = 0;
                try {
                    serNo = terTempData.getValidSerNo(aBaseHandleObj);
                    remoteControl.iSerNO = serNo;
                    return builtRemoteControlPkg(conn, serNo, aBaseHandleObj);
                } catch (Exception e) {
                    // 清除流水号
                    terTempData.getSerNoAndDel(serNo);
                    return null;
                }
            }
        } catch (Exception e) {
            if (byteBuf != null) {
                byteBuf.clear();
            }
            logger.error("构造下行数据包异常", e);
            return null;
        }
    }

    public ByteBuf builtSyncParamRsp(AConnInfo info, int serNo, int syncTime, String syncValue) {
        ByteBuf byteBuf = null;
        try {
            byteBuf = PooledByteBufAllocator.DEFAULT.directBuffer();
            WA206Head wa206Head = getWA206Head(info, (byte) serNo);
            wa206Head.cmd = WA206Head.SyncParamCmdRsp;
            byteBuf = wa206Head.writePkgByte(byteBuf);
//region body
            int start = byteBuf.readableBytes();
            byteBuf.writeInt(syncTime);
            byte[] paramBytes = syncValue.getBytes(CharsetName.US_ASCII);
            byteBuf.writeBytes(paramBytes);
            int end = byteBuf.readableBytes();
            if ((wa206Head.version % 2) != 0) {
                byteBuf = encryptBody(byteBuf, start, end);
            }
//endregion
            // 设置长度
            byteBuf.setShort(2, byteBuf.readableBytes() + 2);
            byteBuf.writeShort(ProtocolUtil.GetCrcByteArray(byteBuf, 2, byteBuf.readableBytes() - 2));//校验和
            return byteBuf;
        } catch (Exception e) {
            byteBuf.clear();
            logger.error("构造下行数据包异常", e);
            return null;
        }
    }

    public ByteBuf builtGetFirmwareRsp(AConnInfo info, ATerPkg aTerPkg, byte[] data) {
        GetFirmware getFirmware = (GetFirmware) aTerPkg;
        ByteBuf byteBuf = null;
        try {
            byteBuf = PooledByteBufAllocator.DEFAULT.directBuffer();
            // 不判定null，理论上不会是null
            WA206Head wa206Head = getWA206Head(info, (byte) getFirmware.head.getSerNo());
            wa206Head.cmd = WA206Head.GetFirmwareCmdRsp;
            byteBuf = wa206Head.writePkgByte(byteBuf);
//region body
            int start = byteBuf.readableBytes();
            byteBuf.writeByte(1);
            byteBuf.writeShort(getFirmware.customerCode);
            byteBuf.writeShort(getFirmware.hardwareModel);
            byteBuf.writeMedium(getFirmware.version);
            byteBuf.writeShort(getFirmware.blockNum);
            byteBuf.writeBytes(data);
            byteBuf.writeShort(ProtocolUtil.GetCrcByteArray(data, 0, data.length));//校验和
            int end = byteBuf.readableBytes();
            if ((wa206Head.version % 2) != 0) {
                byteBuf = encryptBody(byteBuf, start, end);
            }
//endregion
            // 设置长度
            byteBuf.setShort(2, byteBuf.readableBytes() + 2);
            byteBuf.writeShort(ProtocolUtil.GetCrcByteArray(byteBuf, 2, byteBuf.readableBytes() - 2));//校验和
            return byteBuf;
        } catch (Exception e) {
            byteBuf.clear();
            logger.error("构造下行数据包异常", e);
            return null;
        }
    }



    @Override
    public List<ATerPkg> analyzeTerPkg(AConnInfo conn, ByteBuf in) {
        LinkedList<ATerPkg> result = new LinkedList<>();
        int crcCodeCal = 0;// 校验和
        int crcCodePkg = 0;
        int code = ErrorCode.OK;// 错误代码
        int inv = in.readerIndex();
        while (in.readableBytes() > WA206Head.HeadLen) {
            short startCode = in.getShort(inv);
            if (startCode == WA206Head.StartCode) {
                WA206Head head = new WA206Head();
                code = head.InitPkg(in, inv, WA206Head.HeadLen);
                if (code == ErrorCode.OK) {
                    inv += WA206Head.HeadLen;
                    // 判断长度和校验和
                    if (in.readableBytes() >= head.pkgLen) {
                        crcCodeCal = ProtocolUtil.GetCrcByteArray(in, inv - 8, head.pkgLen - 4);
                        crcCodePkg = in.getShort(inv - WA206Head.HeadLen + head.pkgLen - 2);
                        if (crcCodeCal == crcCodePkg) {
                            ATerPkg body = null;
                            byte[] signPkgLog = new byte[0];
                            // 判断是否是加密报文
                            if ((head.version % 2) != 0) {
                                // 完整报文
                                byte[] signPkg = new byte[head.pkgLen];
                                in.getBytes(in.readerIndex(), signPkg);
                                // 取出密文报体
                                byte[] bodyPkg = Arrays.copyOfRange(signPkg, WA206Head.HeadLen, signPkg.length - 2);
                                int bodyPkgLen = bodyPkg.length;
                                // 解密报体
                                bodyPkg = TbitTEAUtil.decrypt(bodyPkg, TbitTEAUtil.KEY);
                                if (bodyPkg != null) {
                                    // 构造明文完整报文
                                    byte[] pkgs = new byte[WA206Head.HeadLen + bodyPkg.length + 2];
                                    System.arraycopy(signPkg, 0, pkgs, 0, WA206Head.HeadLen);
                                    System.arraycopy(bodyPkg, 0, pkgs, WA206Head.HeadLen, bodyPkg.length);
                                    System.arraycopy(signPkg, signPkg.length - 2, pkgs, WA206Head.HeadLen + bodyPkg.length, 2);
                                    // 转换为可存储字符串
                                    signPkgLog = pkgs;
                                    // 构造明文报体
                                    ByteBuf byteBuf = PooledByteBufAllocator.DEFAULT.directBuffer();
                                    byteBuf.writeBytes(new byte[WA206Head.HeadLen]);
                                    byteBuf.writeBytes(bodyPkg);
                                    int headPkglen = head.pkgLen;
                                    // 这里标识实际长度
                                    head.pkgLen -= (bodyPkgLen - bodyPkg.length);
                                    TerGatewayData.updateVerAndRev(conn, head.version, head.reserve);
                                    //TODO 解析数据(重要)
                                    body = analyzeSignPkg(byteBuf, WA206Head.HeadLen, head);
                                    byteBuf.release();
                                    // 还原长度
                                    head.pkgLen = headPkglen;
                                } else {
                                    head.version = (byte) (head.version & 0xfe);
                                    TerGatewayData.updateVerAndRev(conn, head.version, head.reserve);
                                    signPkg = new byte[head.pkgLen];
                                    in.getBytes(in.readerIndex(), signPkg);
                                    signPkgLog = signPkg;
                                    body = analyzeSignPkg(in, inv, head);
                                }
                            } else {
                                byte[] signPkg = new byte[head.pkgLen];
                                in.getBytes(in.readerIndex(), signPkg);
                                signPkgLog = signPkg;
                                TerGatewayData.updateVerAndRev(conn, head.version, head.reserve);
                                body = analyzeSignPkg(in, inv, head);
                            }
                            if (body != null) {
                                body.setConnId(conn.connId);
                                body.setProName(getProtocolName());
                                result.add(body);
                                if (body.autoRsp()) {
                                    final ByteBuf rspData = body.getRsp(conn, this);
                                    if (null != rspData && rspData.readableBytes() > 0) {
                                        conn.downMsg(rspData);
                                    }
                                }
                                body.signPkg = signPkgLog;
                            }
                            inv += (head.pkgLen - WA206Head.HeadLen);
                            in.skipBytes(head.pkgLen);
                        } else {
                            code = ErrorCode.ErrorCheckSum;
                            break;
                        }
                    } else {
                        break;
                    }
                }
            } else {
                code = ErrorCode.ErrorStartCode;
                break;
            }
        }
        if (code != ErrorCode.OK) {
            logger.info(String.format("报文解析错误:%s，主动断开连接", ErrorCode.ErrorString(code)));
            in.release();
            in.clear();
            conn.closeConn();
        }
        return result;
    }

    public ATerPkg analyzeLoginInfo(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        Login aTerBasePkg = new Login();
        aTerBasePkg.head = head;
        inv += analyzeTerMno(head, aTerBasePkg, in, inv);

        aTerBasePkg.dt = ProtocolUtil.BinGetTime(in, inv);
        inv += 4;
        aTerBasePkg.bootReason = in.getByte(inv);
        inv++;
        aTerBasePkg.imsi = ProtocolUtil.BinGetBcd(in, inv, 8, 'F');
        inv += 8;
        aTerBasePkg.imei = ProtocolUtil.BinGetBcd(in, inv, 8, 'F');
        inv += 8;
        aTerBasePkg.funCode = ProtocolUtil.BinGetBcd(in, inv, 2);
        inv += 2;
        aTerBasePkg.factoryCode = ProtocolUtil.BinGetAsciiStringTrimZero(in, inv, 8);
        inv += 8;
        aTerBasePkg.softVersion = ProtocolUtil.BinGetAsciiString(in, inv, len - inv);
        return aTerBasePkg;
    }

    public ATerPkg analyzeAlarmInfo(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        AlarmInfo aTerBasePkg = new AlarmInfo();
        aTerBasePkg.head = head;
        inv += analyzeTerMno(head, aTerBasePkg, in, inv);
        aTerBasePkg.dt = ProtocolUtil.BinGetTime(in, inv);
        inv += 4;
        aTerBasePkg.alarmType = in.getUnsignedByte(inv);
        inv += 1;
        aTerBasePkg.errCodeBytes = new byte[12];
        in.getBytes(inv, aTerBasePkg.errCodeBytes);
        if (aTerBasePkg.alarmType == 8) {
            StringBuilder sb = new StringBuilder();
            List<Integer> alarmExCode = new LinkedList<>();
            // 解析扩展码
            int flag = aTerBasePkg.errCodeBytes[9] & 0xff;
            if ((flag & (0x1 << 0)) != 0) {
                alarmExCode.add(AlarmExCode.BATTERY_LOCK_ERROR);
            }
            if ((flag & (0x1 << 1)) != 0) {
                alarmExCode.add(AlarmExCode.BLE_ERROR);
            }
            if ((flag & (0x1 << 2)) != 0) {
                alarmExCode.add(AlarmExCode.ECU_ERROR);
            }
            if ((flag & (0x1 << 3)) != 0) {
                alarmExCode.add(AlarmExCode.YXZ_ERROR);
            }
            if ((flag & (0x1 << 4)) != 0) {
                alarmExCode.add(AlarmExCode.REAR_LOCK_ERROR);
            }
            if ((flag & (0x1 << 5)) != 0) {
                alarmExCode.add(AlarmExCode.BMS_ERROR);
            }
            if ((flag & (0x1 << 6)) != 0) {
                alarmExCode.add(AlarmExCode.SPEARKER_ERROR);
            }
            flag = aTerBasePkg.errCodeBytes[1] & 0xff;
            if ((flag & (0x1 << 0)) != 0) {
                alarmExCode.add(AlarmExCode.MOTOR_ERROR);
            }
            if ((flag & (0x1 << 3)) != 0) {
                alarmExCode.add(AlarmExCode.NO_POWER_ERROR);
            }
            if ((flag & (0x1 << 5)) != 0) {
                alarmExCode.add(AlarmExCode.ZHUANBA_ERROR);
            }
            flag = aTerBasePkg.errCodeBytes[2] & 0xff;
            if ((flag & (0x1 << 2)) != 0) {
                alarmExCode.add(AlarmExCode.ANTI_RUN_ERROR);
            }
            if ((flag & (0x1 << 5)) != 0) {
                alarmExCode.add(AlarmExCode.BRAKE_ERROR);
            }
            if ((flag & (0x1 << 6)) != 0) {
                alarmExCode.add(AlarmExCode.MOTOR_RUN_ERROR);
            }
            flag = aTerBasePkg.errCodeBytes[3] & 0xff;
            if ((flag & (0x1 << 3)) != 0) {
                alarmExCode.add(AlarmExCode.STALL_ERROR);
            }

            aTerBasePkg.alarmExCode = alarmExCode;
            for (Integer code : aTerBasePkg.alarmExCode) {
                sb.append(AlarmExCode.getExAlarmString(code)).append(",");
            }
            aTerBasePkg.alarmExMsg = sb.toString();
        }
        aTerBasePkg.errCode = ProtocolUtil.BinGetBcd(in, inv, aTerBasePkg.errCodeBytes.length);
        inv += 12;
        return aTerBasePkg;
    }

    public ATerPkg analyzeGetFirmware(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        GetFirmware aTerBasePkg = new GetFirmware();
        aTerBasePkg.head = head;
        inv += analyzeTerMno(head, aTerBasePkg, in, inv);
        aTerBasePkg.customerCode = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.hardwareModel = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.version = in.getMedium(inv);
        inv += 3;
        aTerBasePkg.firmwareType = in.getUnsignedByte(inv);
        inv += 1;
        aTerBasePkg.blockType = in.getUnsignedByte(inv);
        inv += 1;
        aTerBasePkg.blockNum = in.getUnsignedShort(inv);
        inv += 2;
        return aTerBasePkg;
    }

    public ATerPkg analyzeBatteryInfo(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        BatteryInfo aTerBasePkg = new BatteryInfo();
        aTerBasePkg.head = head;
        inv += analyzeTerMno(head, aTerBasePkg, in, inv);
        aTerBasePkg.dt = ProtocolUtil.BinGetTime(in, inv);
        inv += 4;

        boolean bWa206CFlag = ((WA206Head) head).isWA206CVersion();
        aTerBasePkg.soc = in.getUnsignedByte(inv);
        inv += 1;
        if (bWa206CFlag) {
            //跳过2字节可用容量
            aTerBasePkg.batteryRemaining = in.getUnsignedShort(inv);
            inv += 2;
            // 跳过1字节绝对soc
            aTerBasePkg.batteryRelativelyRemaining = in.getUnsignedByte(inv);
            inv += 1;
            // 跳过2字节绝对满电容量
            aTerBasePkg.batteryElectricity = in.getUnsignedShort(inv);
            inv += 2;
        }
        aTerBasePkg.soh = in.getUnsignedByte(inv);
        inv += 1;
        if (bWa206CFlag) {
            aTerBasePkg.batteryTemp = in.getUnsignedShort(inv) + ConstDefine.TEMP_KELVINS;
            inv += 2;
            aTerBasePkg.batteryEI = in.getUnsignedShort(inv);
            inv += 2;
            aTerBasePkg.batteryEU = in.getUnsignedShort(inv) * wa206Head.GetEUUnit();
            inv += 2;
            aTerBasePkg.dischargeCnt = in.getUnsignedShort(inv);
            inv += 2;
            // 14字节 1～7 节电池电压
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 7; i++) {
                sb.append(String.format("%d,", in.getUnsignedShort(inv + i * 2)));
            }
            aTerBasePkg.power1_7 = sb.toString();
            inv += 14;
            // 14字节 8～14 节电池电压
            sb = new StringBuilder();
            for (int i = 0; i < 7; i++) {
                sb.append(String.format("%d,", in.getUnsignedShort(inv + i * 2)));
            }
            aTerBasePkg.power8_14 = sb.toString();
            inv += 14;
            //  2字节 当前充电间隔时间
            aTerBasePkg.currChargeInv = in.getUnsignedShort(inv);
            inv += 2;
            //  2字节 最大充电间隔时间
            aTerBasePkg.maxChargeInv = in.getUnsignedShort(inv);
            inv += 2;
            // 16字节 读写成本条形码
            aTerBasePkg.codeStr = ProtocolUtil.BinGetAsciiStringTrimZero(in, inv, 16);
            inv += 16;
            // 2字节 读版本号
            aTerBasePkg.batteryVer = String.format("%d,%d", in.getUnsignedByte(inv), in.getUnsignedByte(inv + 1));
            inv += 2;
            // 16字节 电池组制造厂名称
            aTerBasePkg.factoryName = ProtocolUtil.BinGetAsciiStringTrimZero(in, inv, 16);
            inv += 16;
            // 解析扩充内容
            if (len - inv >= 10) {
                aTerBasePkg.innerTemp2 = in.getUnsignedShort(inv);
                inv += 2;
                aTerBasePkg.innerTemp3 = in.getUnsignedShort(inv);
                inv += 2;
                aTerBasePkg.innerTemp4 = in.getUnsignedShort(inv);
                inv += 2;
                aTerBasePkg.innerMosTemp = in.getUnsignedShort(inv);
                inv += 2;
                aTerBasePkg.innerMoisture = in.getUnsignedShort(inv);
                inv += 2;
            }
        } else {
            aTerBasePkg.batteryTemp = in.getInt(inv);
            inv += 4;
            aTerBasePkg.batteryEI = in.getInt(inv);
            inv += 4;
            aTerBasePkg.batteryEU = in.getInt(inv) * wa206Head.GetEUUnit();
            inv += 4;
            aTerBasePkg.dischargeCnt = in.getUnsignedShort(inv);
            inv += 2;
            aTerBasePkg.batteryStatus = ProtocolUtil.BinGetBcd(in, inv, 4);
            inv += 4;
        }

        return aTerBasePkg;
    }

    public ATerPkg analyzeGetParamRsp(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        GetParamRsp aTerBasePkg = new GetParamRsp();
        aTerBasePkg.head = head;
        aTerBasePkg.dt = new Date();
        if (wa206Head.TerRspExistMno()) {
            inv += analyzeTerMno(head, aTerBasePkg, in, inv);
        }
        aTerBasePkg.kv = ProtocolUtil.BinGetAsciiString(in, inv, len - inv);
        int index = aTerBasePkg.kv.lastIndexOf(";");
        aTerBasePkg.serNoStr = aTerBasePkg.kv.substring(index + 1, aTerBasePkg.kv.length());
        // 部分设备返回带有 \0 格式一下
        aTerBasePkg.serNoStr = aTerBasePkg.serNoStr.replaceAll("\0", "");
        aTerBasePkg.kv = aTerBasePkg.kv.substring(0, index);
        aTerBasePkg.serNo = wa206Head.serNo;
        return aTerBasePkg;
    }

    public ATerPkg analyzeHeart(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        Heart aTerBasePkg = new Heart();
        aTerBasePkg.head = head;
        inv += analyzeTerMno(head, aTerBasePkg, in, inv);
        aTerBasePkg.dt = new Date();
        aTerBasePkg.signStatus = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.terStatus = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.powerEU = in.getUnsignedShort(inv) * wa206Head.GetEUUnit();
        inv += 2;
        boolean bWa206CFlag = ((WA206Head) head).isWA206CVersion();
        if (bWa206CFlag) {
            // 1字节 相对soc
            aTerBasePkg.soc = in.getUnsignedByte(inv);
            aTerBasePkg.batteryRelativelyRemaining = in.getUnsignedByte(inv);
            inv += 1;
            // 2字节 可用剩余容量
            aTerBasePkg.batteryRemaining = in.getUnsignedShort(inv);
            inv += 2;
        } else {
            aTerBasePkg.soc = -1;
        }
        return aTerBasePkg;
    }

    public ATerPkg analyzePosInfo(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        PosInfo aTerBasePkg = new PosInfo();
        aTerBasePkg.head = head;
        inv += analyzeTerMno(head, aTerBasePkg, in, inv);
        aTerBasePkg.dt = ProtocolUtil.BinGetTime(in, inv);
        inv += 4;
        aTerBasePkg.lat = ProtocolUtil.BinGetLatLon(in, inv);
        inv += 4;
        aTerBasePkg.lon = ProtocolUtil.BinGetLatLon(in, inv);
        inv += 4;
        if ((WA206Head.isXiaomuji(aTerBasePkg.mno) && (((WA206Head) head).is111PosInfo() || ((WA206Head) head).is100PosInfo()))
                || ((WA206Head) head).isPosEx()) {
            aTerBasePkg.high = in.getUnsignedByte(inv) * 16;
            inv += 1;
            aTerBasePkg.pointUnit = in.getUnsignedByte(inv);
            inv++;
            short temp = in.getUnsignedByte(inv);
            inv++;
            aTerBasePkg.dir = ((temp >> 5) & 0x7) * 45;
            aTerBasePkg.signalLevel = temp & 0x1f;
        } else {
            aTerBasePkg.high = in.getUnsignedShort(inv);
            inv += 2;
            aTerBasePkg.dir = in.getUnsignedByte(inv) * 2;
            inv++;
        }
        aTerBasePkg.speed = in.getUnsignedByte(inv);
        inv++;
        aTerBasePkg.signalStatus = in.getUnsignedShort(inv);
        inv += 2;

        aTerBasePkg.mcc = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.mnc = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.lac = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.cellid = in.getUnsignedShort(inv);
        inv += 2;

        //这里判断新中控电量
        aTerBasePkg.soc = in.getUnsignedByte(inv);
        aTerBasePkg.batteryRelativelyRemaining = in.getUnsignedByte(inv);
        inv += 1;
        // 判断是否是206c的版本 这个版本增加了一个2字节的电池容量，暂时为了快速开发，先丢弃掉，用原来的电压
        if (((WA206Head) head).isWA206CVersion() || WA206Head.isXiaomuji(aTerBasePkg.mno)) {
            aTerBasePkg.batteryRemaining = in.getUnsignedShort(inv);
            inv += 2;
        }
        aTerBasePkg.soh = in.getUnsignedByte(inv);
        inv += 1;
        aTerBasePkg.dischargeCnt = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.movingEI = in.getUnsignedByte(inv);
        inv += 1;
        aTerBasePkg.controlTemp = in.getUnsignedByte(inv);
        inv += 1;
        aTerBasePkg.powEU = in.getUnsignedShort(inv) * wa206Head.GetEUUnit();
        inv += 2;
        aTerBasePkg.totalMile = in.getInt(inv);
        inv += 4;
        aTerBasePkg.signMile = in.getInt(inv);
        inv += 4;
        aTerBasePkg.hallSpeed = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.terStatus = in.getUnsignedShort(inv);
        inv += 2;
        return aTerBasePkg;
    }

    public ATerPkg analyzeRemoteControlRsp(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        RemoteControlRsp aTerBasePkg = new RemoteControlRsp();
        aTerBasePkg.head = head;
        aTerBasePkg.dt = new Date();
        if (wa206Head.TerRspExistMno()) {
            inv += analyzeTerMno(head, aTerBasePkg, in, inv);
        }
        aTerBasePkg.ret = in.getUnsignedByte(inv);
        inv += 1;
        aTerBasePkg.serNoStr = ProtocolUtil.BinGetAsciiString(in, inv, len - inv);
        // 部分设备返回带有 \0 格式一下
        aTerBasePkg.serNoStr = aTerBasePkg.serNoStr.replaceAll("\0", "");
        aTerBasePkg.serNo = wa206Head.serNo;
        return aTerBasePkg;
    }

    /**
     * 第二种上报方式，控制指令包含0x3d
     *
     * @param in
     * @param inv
     * @param head
     * @return
     */
    public ATerPkg analyzeRemoteControlRsp2(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        int temp = inv;
        RemoteControlRspTwo aTerBasePkg = new RemoteControlRspTwo();
        aTerBasePkg.head = head;
        aTerBasePkg.dt = new Date();
        if (wa206Head.TerRspExistMno()) {
            inv += analyzeTerMno(head, aTerBasePkg, in, inv);
        }
        aTerBasePkg.ret = in.getUnsignedByte(inv);
        inv += 1;
        aTerBasePkg.extendType = in.getUnsignedByte(inv);
        inv += 1;
        if (aTerBasePkg.extendType == 0x01) {
            //摄像头
            Camera camera = new Camera();
            camera.cameraVersion = ProtocolUtil.BinGetBcd(in, inv, 4, 'F');
            inv += 4;
            camera.cameraErrorCode = in.getUnsignedByte(inv);
            inv += 1;
            camera.similar = in.getUnsignedByte(inv);
            inv += 1;
            camera.picDir = in.getUnsignedInt(inv);
            inv += 4;

            //赋值
            aTerBasePkg.isCamera = true;
            aTerBasePkg.camera = camera;

        } else if (aTerBasePkg.extendType == 0x02) {
            //nfc
            RFID rfid = new RFID();
            //获取卡号:12字节
            //0～7 UID
            rfid.UIDLength=8;
            byte[] uidByte = new byte[8];
            in.getBytes(inv, uidByte);
            StringBuilder uidStr = new StringBuilder();
            for (int i = 0; i < uidByte.length; i++) {
                String b = ByteUtil.ByteToHexString(uidByte[i]);
                if (i == (uidByte.length - 1)) {
                    uidStr.append(b);
                } else {
                    uidStr.append(b).append(":");
                }
            }
            rfid.UID = uidStr.toString();
            inv += 8;
            byte[] siteIdByte = new byte[4];
            in.getBytes(inv, siteIdByte);
            StringBuilder siteIdStr = new StringBuilder();
            for (int i = 0; i < siteIdByte.length; i++) {
                String b = ByteUtil.ByteToHexString(siteIdByte[i]);
                if (i == (siteIdByte.length - 1)) {
                    siteIdStr.append(b);
                } else {
                    siteIdStr.append(b).append(":");
                }
            }
            //8~11字节
            rfid.siteId = siteIdStr.toString();
            inv += 4;
            rfid.nfcControlType = in.getUnsignedShort(inv);
            inv += 2;
            rfid.cnt = in.getUnsignedInt(inv);
            inv += 4;

            //赋值
            aTerBasePkg.rfid = rfid;
            aTerBasePkg.isrfid = true;

        } else if (aTerBasePkg.extendType == 0x03) {
            RFID rfid = new RFID();
            rfid.UIDLength = in.getUnsignedByte(inv);
            inv++;
            byte[] uidByte = new byte[rfid.UIDLength];
            in.getBytes(inv,uidByte);
            StringBuilder uidStr = new StringBuilder();
            for (int i = 0; i < uidByte.length; i++) {
                String b = ByteUtil.ByteToHexString(uidByte[i]);
                if (i == (uidByte.length - 1)){
                    uidStr.append(b);
                } else {
                    uidStr.append(b).append(":");
                }
            }
            rfid.UID = uidStr.toString();
            inv += rfid.UIDLength;
            byte[] siteIdByte = new byte[4];
            in.getBytes(inv, siteIdByte);
            StringBuilder siteIdStr = new StringBuilder();
            for (int i = 0; i < siteIdByte.length; i++) {
                String b = ByteUtil.ByteToHexString(siteIdByte[i]);
                if (i == (siteIdByte.length - 1)) {
                    siteIdStr.append(b);
                } else {
                    siteIdStr.append(b).append(":");
                }
            }
            //8~11字节
            rfid.siteId = siteIdStr.toString();
            inv += 4;
            rfid.nfcControlType = in.getUnsignedShort(inv);
            inv += 2;
            rfid.cnt = in.getUnsignedInt(inv);
            inv += 4;

            //赋值
            aTerBasePkg.rfid = rfid;
            aTerBasePkg.isrfid = true;

        } else {
            logger.error("0xb6 解析扩展字错误");
            return null;//目前不支持其他情况
        }
        aTerBasePkg.serNoStr = ProtocolUtil.BinGetAsciiString(in, inv, len - (inv - temp) - WA206Head.HeadLen);
        // 部分设备返回带有 \0 格式一下
        aTerBasePkg.serNoStr = aTerBasePkg.serNoStr.replaceAll("\0", "");
        aTerBasePkg.serNo = wa206Head.serNo;
        return aTerBasePkg;
    }

    public ATerPkg analyzeRemoteControlVoiceRsp(ByteBuf in, int inv, ATerPkgHead
            head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        RemoteConVoiceRsp aTerBasePkg = new RemoteConVoiceRsp();
        aTerBasePkg.head = head;
        aTerBasePkg.dt = new Date();

        if (wa206Head.isWA206CVersion()) {
            // 如果有设备编号去掉5字节
            if (wa206Head.TerRspExistMno()) {
                inv += analyzeTerMno(head, aTerBasePkg, in, inv);
            }
            // 4字节 时间戳
            inv += 4;
            // 1字节 执行结果
            aTerBasePkg.ret = in.getUnsignedByte(inv);
            inv += 1;
            // 命令
            inv += 2;
        } else {
            aTerBasePkg.ret = in.getUnsignedByte(inv);
            inv += 1;
        }

        aTerBasePkg.serNoStr = ProtocolUtil.BinGetAsciiString(in, inv, len - inv);
        // 部分设备返回带有 \0 格式一下
        aTerBasePkg.serNoStr = aTerBasePkg.serNoStr.replaceAll("\0", "");
        aTerBasePkg.serNo = wa206Head.serNo;
        return aTerBasePkg;
    }

    public ATerPkg analyzeRemoteSmsRsp(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        RemoteSmsRsp aTerBasePkg = new RemoteSmsRsp();
        aTerBasePkg.head = head;
        inv += analyzeTerMno(head, aTerBasePkg, in, inv);
        aTerBasePkg.dt = new Date();
        aTerBasePkg.ret = in.getUnsignedByte(inv);
        aTerBasePkg.serNo = wa206Head.serNo;
        return aTerBasePkg;
    }

    public ATerPkg analyzeSetParamRsp(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        SetParamRsp aTerBasePkg = new SetParamRsp();
        aTerBasePkg.head = head;
        aTerBasePkg.dt = new Date();
        if (wa206Head.TerRspExistMno()) {
            inv += analyzeTerMno(head, aTerBasePkg, in, inv);
        }
        aTerBasePkg.kv = ProtocolUtil.BinGetAsciiString(in, inv, len - inv);
        int index = aTerBasePkg.kv.lastIndexOf(";");
        aTerBasePkg.serNoStr = aTerBasePkg.kv.substring(index + 1, aTerBasePkg.kv.length());
        // 部分设备返回带有 \0 格式一下
        aTerBasePkg.serNoStr = aTerBasePkg.serNoStr.replaceAll("\0", "");
        aTerBasePkg.kv = aTerBasePkg.kv.substring(0, index);
        aTerBasePkg.serNo = wa206Head.serNo;
        return aTerBasePkg;
    }

    public ATerPkg analyzeSmsUpload(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        SmsUpload aTerBasePkg = new SmsUpload();
        aTerBasePkg.head = head;
        inv += analyzeTerMno(head, aTerBasePkg, in, inv);
        aTerBasePkg.dt = new Date();

        aTerBasePkg.phone = ProtocolUtil.BinGetBcd(in, inv, 10, 'F');
        inv += 10;
        int contentByteLen = len - 27;
        if (contentByteLen % 2 == 1) {
            contentByteLen--;
        }
        aTerBasePkg.content = ProtocolUtil.BinGetString(in, inv, contentByteLen, CharsetName.UTF_16LE);
        return aTerBasePkg;
    }

    public ATerPkg analyzeSyncParam(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        SyncParam aTerBasePkg = new SyncParam();
        aTerBasePkg.head = head;
        inv += analyzeTerMno(head, aTerBasePkg, in, inv);
        aTerBasePkg.syncTick = in.getInt(inv);
        return aTerBasePkg;
    }

    public ATerPkg analyzeTerInfoUpload(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        TerInfoUpload aTerBasePkg = new TerInfoUpload();
        aTerBasePkg.head = head;
        inv += analyzeTerMno(head, aTerBasePkg, in, inv);
        aTerBasePkg.dt = ProtocolUtil.BinGetTime(in, inv);
        inv += 4;
        aTerBasePkg.eventType = in.getUnsignedByte(inv);
        inv += 1;
        aTerBasePkg.lat = ProtocolUtil.BinGetLatLon(in, inv);
        inv += 4;
        aTerBasePkg.lon = ProtocolUtil.BinGetLatLon(in, inv);
        inv += 4;
        aTerBasePkg.high = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.dir = in.getUnsignedByte(inv) * 2;
        inv++;
        aTerBasePkg.speed = in.getUnsignedByte(inv);
        inv++;
        aTerBasePkg.signalStatus = in.getUnsignedShort(inv);
        inv += 2;

        aTerBasePkg.mcc = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.mnc = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.lac = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.cellid = in.getUnsignedShort(inv);
        inv += 2;

        aTerBasePkg.soc = in.getUnsignedByte(inv);
        inv += 1;
        // 判断是否是206c的版本 这个版本增加了一个2字节的电池容量，暂时为了快速开发，先丢弃掉，用原来的电压
        if (((WA206Head) head).isWA206CVersion()) {
            inv += 2;
        }
        aTerBasePkg.powEU = in.getUnsignedShort(inv) * wa206Head.GetEUUnit();
        inv += 2;
        aTerBasePkg.totalMile = in.getInt(inv);
        inv += 4;
        aTerBasePkg.signMile = in.getInt(inv);
        inv += 4;
        aTerBasePkg.terStatus = in.getUnsignedShort(inv);
        inv += 2;
        return aTerBasePkg;
    }

    public ATerPkg analyzeCarStatusUpload(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        CarStatusUpload aTerBasePkg = new CarStatusUpload();
        aTerBasePkg.head = head;
        inv += analyzeTerMno(head, aTerBasePkg, in, inv);
        aTerBasePkg.dt = ProtocolUtil.BinGetTime(in, inv);
        inv += 4;
        aTerBasePkg.lastTime = in.getUnsignedShort(inv);
        inv += 2;

        int key = in.getUnsignedShort(inv);
        inv += 2;
        int secLen = in.getUnsignedShort(inv);
        inv += 2;
        analyzeExCarData(in, inv, key, secLen, aTerBasePkg);

        inv += secLen;
        key = in.getUnsignedShort(inv);
        inv += 2;
        secLen = in.getUnsignedShort(inv);
        inv += 2;
        analyzeExCarData(in, inv, key, secLen, aTerBasePkg);

        inv += secLen;
        key = in.getUnsignedShort(inv);
        inv += 2;
        secLen = in.getUnsignedShort(inv);
        inv += 2;
        analyzeExCarData(in, inv, key, secLen, aTerBasePkg);
        inv += secLen;
        return aTerBasePkg;
    }

    public ATerPkg analyzeTerStatusChange(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        TerStatusChange aTerBasePkg = new TerStatusChange();
        aTerBasePkg.head = head;
        int index = 0;
        index += analyzeTerMno(head, aTerBasePkg, in, inv + index);
        aTerBasePkg.dt = ProtocolUtil.BinGetTime(in, inv + index);
        index += 4;
        aTerBasePkg.changeItemList = new LinkedList<>();
        while (len - index > 2) {
            int type = in.getUnsignedByte(inv + index);
            index += 1;
            int statusLen = in.getUnsignedByte(inv + index);
            index += 1;
            if (type == 1) {
                TSCMaxVol maxVol = new TSCMaxVol();
                maxVol.type = type;
                maxVol.len = statusLen;
                maxVol.maxVol = in.getUnsignedShort(inv + index);
                index += 2;
                aTerBasePkg.changeItemList.add(maxVol);
            } else {
                index += statusLen;
            }
        }
        return aTerBasePkg;
    }

    public ATerPkg analyzeBmsFaultInfo(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        BmsFaultInfo pkg = new BmsFaultInfo();
        pkg.head = head;
        int index = 0;
        index += analyzeTerMno(head, pkg, in, inv + index);
        pkg.dt = ProtocolUtil.BinGetTime(in, inv + index);
        index += 4;
        // 16字节 读写成本条形码
        pkg.codeStr = ProtocolUtil.BinGetAsciiStringTrimZero(in, inv + index, 16);
        index += 16;
        pkg.dtStr = String.format("%d-%d-%d %d:%d:%d",
                2000 + in.getUnsignedByte(inv + index + 0),
                in.getUnsignedByte(inv + index + 1),
                in.getUnsignedByte(inv + index + 2),
                in.getUnsignedByte(inv + index + 3),
                in.getUnsignedByte(inv + index + 4),
                in.getUnsignedByte(inv + index + 5));
        index += 6;
        pkg.u = in.getUnsignedInt(inv + index);
        index += 4;
        pkg.i = in.getInt(inv + index);
        index += 4;
        for (int i = 0; i < 5; i++) {
            pkg.tempList.add(in.getUnsignedShort(inv + index));
            index += 2;
        }
        pkg.humidity = in.getUnsignedShort(inv + index);
        index += 2;
        for (int i = 0; i < 16; i++) {
            pkg.uList.add(in.getUnsignedShort(inv + index));
            index += 2;
        }
        pkg.batteryRemaining = in.getUnsignedShort(inv + index);
        index += 2;
        pkg.batteryElectricity = in.getUnsignedShort(inv + index);
        index += 2;
        pkg.dischargeCnt = in.getUnsignedShort(inv + index);
        index += 2;
        pkg.soc = in.getUnsignedByte(inv + index);
        index += 1;
        pkg.batteryStatus = ProtocolUtil.BinGetBcd(in, inv + index, 4);
        inv += 4;
        pkg.flag = ProtocolUtil.BinGetBcd(in, inv + index, 2);
        inv += 2;

        return pkg;
    }

    public ATerPkg analyzeTerUploadData(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int dataLen = wa206Head.pkgLen - 10 - 2;
        TerUploadData aTerBasePkg = new TerUploadData();
        aTerBasePkg.head = head;
        int index = 0;
        aTerBasePkg.mno = ProtocolUtil.BinGetBcd(in, inv, 9, 'F');
        index += 9;
        aTerBasePkg.dt = ProtocolUtil.BinGetTime(in, inv + index);
        index += 4;
        while (dataLen - index >= 4) {
            XiaomujiBase item = null;
            String key = ProtocolUtil.BinGetBcd(in, inv + index, 2);
            index += 2;
            int valueLen = in.getUnsignedShort(inv + index);
            index += 2;
            if (dataLen - index >= valueLen) {
                if (Objects.equals(key, "1603")) {
                    int value = in.getShort(inv + index);
                    item = new XiaomujiCalRet(value, key, valueLen);
                } else if (Objects.equals(key, "160B")) {
                    int value = in.getShort(inv + index);
                    item = new XiaomujiCalRecoup(value, key, valueLen);
                } else {
                    String value = ProtocolUtil.BinGetBcd(in, inv + index, valueLen);
                    item = new XiaomujiTlv(value, key, valueLen);
                }
                index += item.getLen();
                if (null != item) {
                    aTerBasePkg.kvList.add(item);
                }
            } else {
                break;
            }
        }
        return aTerBasePkg;
    }

    public ATerPkg analyzeTerSpot(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        TerSpotData aTerBasePkg = new TerSpotData();
        aTerBasePkg.head = head;
        int index = 0;
        index += analyzeTerMno(head, aTerBasePkg, in, inv + index);
        aTerBasePkg.dt = ProtocolUtil.BinGetTime(in, inv + index);
        index += 4;
        aTerBasePkg.spotItems = new LinkedList<>();
        while (len - index - inv >= 4) {
            int spotType = in.getUnsignedShort(inv + index);
            index += 2;
            int spotDataLen = in.getUnsignedShort(inv + index);
            index += 2;
            String spotContent = in.getCharSequence(inv + index, spotDataLen, CharsetUtil.US_ASCII).toString();
            index += spotDataLen;
            TerSpotItem item = new TerSpotItem(spotType, spotDataLen, spotContent);
            aTerBasePkg.spotItems.add(item);
        }
        return aTerBasePkg;
    }

    public ATerPkg anayzeMuPosUploadCmd(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        MuPosUpload pkg = new MuPosUpload();
        pkg.head = head;
        int index = 0;
        index += analyzeTerMno(head, pkg, in, inv + index);
        pkg.dt = ProtocolUtil.BinGetTime(in, inv + index);
        index += 4;
        pkg.dataFlag = in.getUnsignedShort(inv + index);
        index += 2;
        pkg.posCount = in.getUnsignedByte(inv + index);
        index += 1;
        for (int i = 0; i < pkg.posCount; i ++) {
            MuPos pos = new MuPos();
            int posLen = pos.initData(in, inv + index);
            index += posLen;
            pkg.posList.add(pos);
        }
        pkg.cellCount = in.getUnsignedByte(inv + index);
        index ++;
        for (int i = 0; i < pkg.cellCount; i ++) {
            CellInfo ci = new CellInfo();
            ci.mcc = in.getUnsignedShort(inv + index);
            index += 2;
            ci.mnc = in.getUnsignedShort(inv + index);
            index += 2;
            ci.lac = in.getUnsignedShort(inv + index);
            index += 2;
            ci.cellid = in.getUnsignedShort(inv + index);
            index += 2;
            ci.rssi = in.getUnsignedByte(inv + index);
            index ++;
            pkg.cellList.add(ci);
        }
        pkg.totalMile = in.getInt(inv + index);
        index += 4;
        pkg.signMile = in.getInt(inv + index);
        index += 4;
        pkg.hallSpeed = in.getUnsignedShort(inv + index);
        index += 2;
        pkg.terStatus = in.getUnsignedShort(inv + index);
        index += 2;
        pkg.vibA = in.getUnsignedShort(inv + index);
        index += 2;
        pkg.angle = in.getUnsignedShort(inv + index);
        index += 2;
        pkg.tumbleAngle = in.getUnsignedShort(inv + index);
        index += 2;

        pkg.powEU = in.getUnsignedShort(inv + index) * wa206Head.GetEUUnit();
        index += 2;
        pkg.soc = in.getUnsignedByte(inv + index);
        index += 1;
        pkg.batteryRemaining = in.getUnsignedShort(inv+ index);
        index += 2;
        pkg.soh = in.getUnsignedByte(inv + index);
        index += 1;
        pkg.codeStr = ProtocolUtil.BinGetAsciiStringTrimZero(in, inv + index, 16);
        index += 16;
        return pkg;
    }

    public ATerPkg analyzeMixPosUp(ByteBuf in, int inv, ATerPkgHead head) {
        WA206Head wa206Head = (WA206Head) head;
        int len = wa206Head.pkgLen - 2;
        MixPosUp aTerBasePkg = new MixPosUp();
        aTerBasePkg.head = head;
        inv += analyzeTerMno(head, aTerBasePkg, in, inv);
        aTerBasePkg.dt = ProtocolUtil.BinGetTime(in, inv);
        inv += 4;

        aTerBasePkg.lat = ProtocolUtil.BinGetLatLon(in, inv);
        inv += 4;
        aTerBasePkg.lon = ProtocolUtil.BinGetLatLon(in, inv);
        inv += 4;
        aTerBasePkg.high = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.dir = in.getUnsignedByte(inv) * 2;
        inv++;
        aTerBasePkg.speed = in.getUnsignedByte(inv);
        inv++;
        aTerBasePkg.signalStatus = in.getUnsignedShort(inv);
        inv += 2;

        aTerBasePkg.terStatus = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.batteryVoltage = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.bakBatVoltage = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.soc = in.getUnsignedByte(inv);
        inv++;
        aTerBasePkg.reservedData = in.getUnsignedByte(inv);
        inv++;

        int blsDataLen = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.cellInfoList = new LinkedList<>();
        for (int j = 0; j <= blsDataLen - 9; ) {
            CellInfo info = new CellInfo();

            info.mcc = in.getUnsignedShort(inv + j);
            j += 2;
            info.mnc = in.getUnsignedShort(inv + j);
            j += 2;
            info.lac = in.getUnsignedShort(inv + j);
            j += 2;
            info.cellid = in.getUnsignedShort(inv + j);
            j += 2;
            info.rssi = in.getByte(inv + j);
            j++;

            aTerBasePkg.cellInfoList.add(info);
        }
        inv += blsDataLen;
        int wifiDataLen = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.wifiInfoList = new LinkedList<>();
        for (int j = 0; j <= wifiDataLen - 8; ) {
            WifiInfo info = new WifiInfo();
            info.apMAC = ByteUtil.BytesToHexString(in, inv + j, 6);
            j += 6;
            info.apLevel = in.getByte(inv + j);
            j += 1;
            info.reserved = in.getUnsignedByte(inv + j);
            j += 1;

            aTerBasePkg.wifiInfoList.add(info);
        }
        inv += wifiDataLen;
        int bleDataLen = in.getUnsignedShort(inv);
        inv += 2;
        aTerBasePkg.bleInfoList = new LinkedList<>();
        for (int j = 0; j <= bleDataLen - 16; ) {
            BleInfo info = new BleInfo();
            info.bleMAC = ByteUtil.BytesToHexString(in, inv + j, 6);
            j += 6;
            info.bleTID = ByteUtil.BytesToHexString(in, inv + j, 6);
            j += 6;
            info.bleLevel = in.getByte(inv + j);
            j += 1;
            int s = in.getUnsignedMedium(inv + j);
            j += 3;
            // bit22-bit23 扫描到的设备类型：0 ：单车设备信息   1：道钉
            info.bleType = BitUtil.between(s, 22, 24);
            // bit19~bit21 硬件版本号
            info.hdVer = BitUtil.between(s, 19, 22);
            // bit16-18 软件版本号
            info.softVer = BitUtil.between(s, 16, 19);
            // bit0-bit15 蓝牙状态
            info.bleStatus = BitUtil.between(s, 0, 16);

            aTerBasePkg.bleInfoList.add(info);
        }
        inv += bleDataLen;
        return aTerBasePkg;
    }

    private void analyzeExCarData(ByteBuf in, int inv, int key, int len, CarStatusUpload carStatusUpload) {
        List<CarExData> exDataList = carStatusUpload.exDataList;
        List<String> exDataShow = carStatusUpload.exDataShow;
        int i = 0;
        if (key == 0x1402) {
            while (len - i >= 8) {
                CarExData data = new CarExData();
                data.lat = ProtocolUtil.BinGetLatLon(in, inv + i);
                i += 4;
                data.lon = ProtocolUtil.BinGetLatLon(in, inv + i);
                i += 4;
                exDataShow.add(String.format("%f,%f", data.lat, data.lon));
                exDataList.add(data);
            }
        } else if (key == 0x1403) {
            while (len - i >= 4) {
                CarExData data = new CarExData();
                data.speed = in.getUnsignedByte(inv + i);
                i += 1;
                data.iol = in.getUnsignedByte(inv + i);
                i += 1;
                data.highBrake = in.getUnsignedByte(inv + i);
                i += 1;
                data.lowBrake = in.getUnsignedByte(inv + i);
                i += 1;
                exDataShow.add(String.format("%d,%d,%d,%d", data.speed, data.iol, data.highBrake, data.lowBrake));
                exDataList.add(data);
            }
        } else if (key == 0x1404) {
            while (len - i >= 3) {
                CarExData data = new CarExData();
                data.sharkZ = in.getByte(inv + i);
                i += 1;
                data.sharkY = in.getByte(inv + i);
                i += 1;
                data.sharkX = in.getByte(inv + i);
                i += 1;
                exDataShow.add(String.format("%d,%d,%d", data.sharkX, data.sharkY, data.sharkZ));
                exDataList.add(data);
            }
        }
    }

    private int analyzeTerMno(ATerPkgHead head, ATerPkg aTerPkg, ByteBuf in, int inv) {
        // 先取一个做一下判定
        String tempStr = ProtocolUtil.BinGetBcd(in, inv, 5, 'F');
        // 如果是EC开头长度是9位，如果不是EC开头使用以前的规则
        int len;
        if (WA206Head.isXiaomuji(tempStr)) {
            aTerPkg.mno = ProtocolUtil.BinGetBcd(in, inv, 9, 'F');
            len = 9;
        } else {
            if (((WA206Head) head).isTidExVersion()) {
                aTerPkg.mno = ProtocolUtil.BinGetBcd(in, inv, 9, 'F');
                len = 9;
            } else {
                aTerPkg.mno = ProtocolUtil.BinGetBcd(in, inv, 5, 'F');
                len = 5;
            }
        }
        return len;
    }

    public ByteBuf getLoginInfoRsp(AConnInfo info, ATerPkg pkg) {
        WA206Head wa206Head = (WA206Head) pkg.head;
        ByteBuf rsp = getFormatPkgHead(info, WA206Head.LoginCmdRsp, wa206Head.serNo);
//region body
        int start = rsp.readableBytes();
        rsp.writeByte(0);
        rsp.writeInt((int) (System.currentTimeMillis() / 1000));
        int end = rsp.readableBytes();
        if ((wa206Head.version % 2) != 0) {
            rsp = encryptBody(rsp, start, end);
        }
//endregion
        rsp = setLenAndCrc(rsp);
        return rsp;
    }

    public ByteBuf getMixPosUpRsp(AConnInfo info, ATerPkg pkg) {
        WA206Head wa206Head = (WA206Head) pkg.head;
        ByteBuf rsp = getFormatPkgHead(info, WA206Head.MixPosUpCmdRsp, wa206Head.serNo);
//region body
//endregion
        rsp = setLenAndCrc(rsp);
        return rsp;
    }

    public static ByteBuf getCommRspPkg(AConnInfo info, ATerPkg pkg, byte rspCmd) {
        WA206Head wa206Head = (WA206Head) pkg.head;
        ByteBuf rsp = getFormatPkgHead(info, rspCmd, wa206Head.serNo);
//region body
//endregion
        rsp = setLenAndCrc(rsp);
        return rsp;
    }

    public ByteBuf getAlarmInfoRsp(AConnInfo info, ATerPkg pkg) {
        WA206Head wa206Head = (WA206Head) pkg.head;
        ByteBuf rsp = getFormatPkgHead(info, WA206Head.AlarmInfoCmdRsp, wa206Head.serNo);

        rsp = setLenAndCrc(rsp);
        return rsp;
    }

    public ByteBuf getBmsFaultInfoRsp(AConnInfo info, ATerPkg pkg) {
        WA206Head wa206Head = (WA206Head) pkg.head;
        ByteBuf rsp = getFormatPkgHead(info, WA206Head.TerBmsFaultInfoUploadRsp, wa206Head.serNo);

        rsp = setLenAndCrc(rsp);
        return rsp;
    }

    public ByteBuf getSpotDataRsp(AConnInfo info, ATerPkg pkg) {
        WA206Head wa206Head = (WA206Head) pkg.head;
        ByteBuf rsp = getFormatPkgHead(info, WA206Head.TerSpotCmdRsp, wa206Head.serNo);

        rsp = setLenAndCrc(rsp);
        return rsp;
    }

    public ByteBuf getStatusChangeRsp(AConnInfo info, ATerPkg pkg) {
        WA206Head wa206Head = (WA206Head) pkg.head;
        ByteBuf rsp = getFormatPkgHead(info, WA206Head.TerStatusChangeUploadRsp, wa206Head.serNo);

        rsp = setLenAndCrc(rsp);
        return rsp;
    }

    public ByteBuf getTerUploadDataRsp(AConnInfo info, ATerPkg pkg) {
        WA206Head wa206Head = (WA206Head) pkg.head;
        ByteBuf rsp = getFormatPkgHead(info, WA206Head.TerUploadDataCmdRsp, wa206Head.serNo);

        rsp = setLenAndCrc(rsp);
        return rsp;
    }

    public ByteBuf getCarStatusUploadRsp(AConnInfo info, ATerPkg pkg) {
        WA206Head wa206Head = (WA206Head) pkg.head;
        ByteBuf rsp = getFormatPkgHead(info, WA206Head.CarStatusUploadCmdRsp, wa206Head.serNo);

        rsp = setLenAndCrc(rsp);
        return rsp;
    }

    public ByteBuf getGetFirmwareRsp(AConnInfo info, ATerPkg pkg) {
        WA206Head wa206Head = (WA206Head) pkg.head;
        ByteBuf rsp = getFormatPkgHead(info, WA206Head.GetFirmwareCmdRsp, wa206Head.serNo);

        rsp = setLenAndCrc(rsp);
        return rsp;
    }

    public ByteBuf getGetParamRspRsp(AConnInfo info, ATerPkg pkg) {
        return null;
    }

    public ByteBuf getHeartRsp(AConnInfo info, ATerPkg pkg) {
        WA206Head wa206Head = (WA206Head) pkg.head;
        ByteBuf rsp = getFormatPkgHead(info, WA206Head.HeartCmdRsp, wa206Head.serNo);

        rsp = setLenAndCrc(rsp);
        return rsp;
    }

    public ByteBuf getHeartRspData(AConnInfo info, ATerPkg pkg, TerSoftInfo terSoftInfo) {
        WA206Head wa206Head = (WA206Head) pkg.head;
        ByteBuf rsp = getFormatPkgHead(info, WA206Head.HeartCmdRsp, wa206Head.serNo);

        //region 206c body
        if (null != terSoftInfo) {
            int start = rsp.readableBytes();
            rsp.writeByte(0x75);
            rsp.writeByte(0x75);//
            rsp.writeByte(terSoftInfo.softId);//id
            rsp.writeMedium(terSoftInfo.version);
            rsp.writeInt(terSoftInfo.binSize);
            rsp.writeShort(terSoftInfo.binCRC);
            rsp.writeInt(terSoftInfo.time);
            rsp.writeByte(terSoftInfo.enFlag);
            rsp.writeBytes(terSoftInfo.reserveData);
            int end = rsp.readableBytes();
            if ((wa206Head.version % 2) != 0) {
                rsp = encryptBody(rsp, start, end);
            }
        }
        //endregion

        rsp = setLenAndCrc(rsp);
        return rsp;
    }

    public ByteBuf getPosInfoRsp(AConnInfo info, ATerPkg pkg) {
        WA206Head wa206Head = (WA206Head) pkg.head;
        ByteBuf rsp = getFormatPkgHead(info, WA206Head.PosInfoCmdRsp, wa206Head.serNo);

        rsp = setLenAndCrc(rsp);
        return rsp;
    }

    public ByteBuf getRemoteControlVoiceRspRsp(ATerPkg pkg) {
        return null;
    }

    public ByteBuf getBatteryInfoCmd(AConnInfo info, ATerPkg pkg) {
        WA206Head wa206Head = (WA206Head) pkg.head;
        ByteBuf rsp = getFormatPkgHead(info, WA206Head.BatteryInfoCmdRsp, wa206Head.serNo);

        rsp = setLenAndCrc(rsp);
        return rsp;
    }

    public ByteBuf getSmsUploadRsp(AConnInfo info, ATerPkg pkg) {
        WA206Head wa206Head = (WA206Head) pkg.head;
        ByteBuf rsp = getFormatPkgHead(info, WA206Head.SmsUploadCmdRsp, wa206Head.serNo);

        rsp = setLenAndCrc(rsp);
        return rsp;
    }

    public ByteBuf getSyncParamRsp(AConnInfo info, ATerPkg pkg) {
        WA206Head wa206Head = (WA206Head) pkg.head;
        ByteBuf rsp = getFormatPkgHead(info, WA206Head.SyncParamCmdRsp, wa206Head.serNo);

        rsp = setLenAndCrc(rsp);
        return rsp;
    }

    /**
     * 将数据解析成我们对应的数据，并进行封装
     *
     * @param in
     * @param inv
     * @param head
     * @return
     */
    private ATerPkg analyzeSignPkg(ByteBuf in, int inv, WA206Head head) {
        ATerPkg body = null;
        int firstInv = inv;
        int code = ErrorCode.OK;
        try {
            switch (head.cmd) {
                case WA206Head.LoginCmd:
                    body = analyzeLoginInfo(in, inv, head);
                    break;
                case WA206Head.PosInfoCmd:
                    body = analyzePosInfo(in, inv, head);
                    break;
                case WA206Head.BatteryInfoCmd:
                    body = analyzeBatteryInfo(in, inv, head);
                    break;
                case WA206Head.AlarmInfoCmd:
                    body = analyzeAlarmInfo(in, inv, head);
                    break;
                case WA206Head.HeartCmd:
                    body = analyzeHeart(in, inv, head);
                    break;
                case WA206Head.RemoteControlCmdRsp:
                    body = analyzeRemoteControlRsp(in, inv, head);
                    break;
                // 远程控制指令数据包2 0xb6
                case WA206Head.RemoteControlCmdRsp2:
                    body = analyzeRemoteControlRsp2(in, inv, head);
                    break;
                case WA206Head.GetParamCmdRsp:
                    body = analyzeGetParamRsp(in, inv, head);
                    break;
                case WA206Head.SetParamCmdRsp:
                    body = analyzeSetParamRsp(in, inv, head);
                    break;
                case WA206Head.SyncParamCmd:
                    body = analyzeSyncParam(in, inv, head);
                    break;
                case WA206Head.SmsUploadCmd:
                    body = analyzeSmsUpload(in, inv, head);
                    break;
                case WA206Head.RemoteSmsCmdRsp:
                    body = analyzeRemoteSmsRsp(in, inv, head);
                    break;
                case WA206Head.RemoteConVoiceCmdRsp:
                    body = analyzeRemoteControlVoiceRsp(in, inv, head);
                    break;
                case WA206Head.GetFirmwareCmd:
                    body = analyzeGetFirmware(in, inv, head);
                    break;
                case WA206Head.GetTerEventCmd:
                    body = analyzeTerInfoUpload(in, inv, head);
                    break;
                case WA206Head.CarStatusUploadCmd:
                    body = analyzeCarStatusUpload(in, inv, head);
                    break;
                case WA206Head.MixPosUpCmd:
                    body = analyzeMixPosUp(in, inv, head);
                    break;
                case WA206Head.TerStatusChangeUpload:
                    body = analyzeTerStatusChange(in, inv, head);
                    break;
                case WA206Head.TerBmsFaultInfoUpload:
                    body = analyzeBmsFaultInfo(in, inv, head);
                    break;
                case WA206Head.TerUploadDataCmd:
                    body = analyzeTerUploadData(in, inv, head);
                    break;
                case WA206Head.TerSpotCmd:
                    body = analyzeTerSpot(in, inv, head);
                    break;
                case WA206Head.MuPosUploadCmd:
                    body = anayzeMuPosUploadCmd(in, inv, head);
                    break;
                default:
                    code = ErrorCode.ErrorUnkonwCmd;
                    break;
            }
        } catch (Exception e) {
            code = ErrorCode.ErrorAnalyzePkgError;
        }
        if (code == ErrorCode.OK) {
            return body;
        } else {
            logger.info(String.format("报体解析失败:[%s],cmd:[%d],head:[%s],buffer:[%s]",
                    ErrorCode.ErrorString(code), head.cmd, JSON.toJSONString(head), ProtocolUtil.BinGetBcd(in, in.readerIndex(), in.readableBytes())));
            logger.info(String.format("报体解析失败:msg:[%s]", ProtocolUtil.BinGetBcd(in, firstInv, head.pkgLen)));
            return null;
        }
    }

    public static ByteBuf getFormatPkgHead(AConnInfo info, byte cmd, byte serNo) {
        ByteBuf rsp = PooledByteBufAllocator.DEFAULT.directBuffer();
        rsp.writeShort(WA206Head.StartCode); // 头
        rsp.writeShort(0);//长度
        rsp.writeByte(info.version);//版本号
        rsp.writeByte(cmd);//命令码
        rsp.writeByte(serNo);//流水号
        rsp.writeMedium(info.reserve);//保留字
        return rsp;
    }

    /**
     * 设置长度和校验和
     *
     * @param byteBuf
     * @return
     */
    public static ByteBuf setLenAndCrc(ByteBuf byteBuf) {
        // 设置长度
        byteBuf.setShort(2, byteBuf.readableBytes() + 2);
        byteBuf.writeShort(ProtocolUtil.GetCrcByteArray(byteBuf, 2, byteBuf.readableBytes() - 2));//校验和
        return byteBuf;
    }

    /**
     * 加密报数据体
     *
     * @param byteBuf
     * @param start
     * @param end
     * @return
     */
    private ByteBuf encryptBody(ByteBuf byteBuf, int start, int end) {

        byte[] body = new byte[end - start];
        //byteBuf.readBytes(body);
        byteBuf.getBytes(start, body);
        byteBuf.writerIndex(start);
        body = TbitTEAUtil.encrypt(body, TbitTEAUtil.KEY);
        return byteBuf.writeBytes(body);
    }

    @Override
    public String getProtocolName() {
        return protocolName;
    }
}
